package com.ybwh.springboot3.service;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.google.common.base.Preconditions;
import com.ybwh.springboot3.common.BusinessException;
import com.ybwh.springboot3.dao.AreaMapper;
import com.ybwh.springboot3.model.po.Area;
import com.ybwh.springboot3.util.BatchActionUtil;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * <p>
 * 测试spring事务管理
 * </p>
 *
 * @author fanbeibei
 * @version V1.0
 * @since 2019/8/14 11:04
 */
@Service
public class AreaService {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private AreaService2 areaService2;
    @Resource
    private AreaMapper areaMapper;



    public void someMethod() {
        // 保存当前数据源
        String originDs = DynamicDataSourceContextHolder.peek();

        try {
            // 强制切换到主库
            DynamicDataSourceContextHolder.push("master"); // 主库名称

            // 执行需要走主库的操作
            // ...
        } finally {
            // 恢复原始数据源
            if (originDs != null) {
                DynamicDataSourceContextHolder.push(originDs);
            } else {
                DynamicDataSourceContextHolder.clear();
            }
        }
    }







    @Transactional(rollbackFor = Exception.class)
    public void addAreaRollBack0(Area area) throws BusinessException {
        Preconditions.checkArgument(null != area, "area is null");

        areaMapper.save(area);
        throw new BusinessException("");

    }

    @Transactional(rollbackFor = Exception.class)
    public void addAreaRollBack1(Area area) throws BusinessException {
        Preconditions.checkArgument(null != area, "area is null");
        areaMapper.save(area);
    }

    //    @Transactional(rollbackFor = Exception.class)
    public void addAreaRollBack2(Area area) throws BusinessException {
        Preconditions.checkArgument(null != area, "area is null");

        addAreaRollBack1(area);
        throw new BusinessException("");

    }


    public void addAreaRollBack3(Area area) throws BusinessException {
        Preconditions.checkArgument(null != area, "area is null");

        addAreaRollBack1(area);
        throw new BusinessException("");

    }


    public void addAreaRollBack4(Area area) throws BusinessException {
        Preconditions.checkArgument(null != area, "area is null");

        areaService2.addAreaRollBack1(area);
        throw new BusinessException("");

    }


    public int batchInsert(List<Area> areaList) {
        Preconditions.checkArgument(null != areaList && areaList.size() > 0, "areaList is null");

        return BatchActionUtil.batchInsertWrap(areaList, 200, new BatchActionUtil.BatchAction<Area, Object>() {
            @Override
            public int insert(List<Area> list) {
                return areaMapper.saveBatchIgnoreNull(list);
            }
        });


    }

    public Area queryById(Long id) {

        return areaMapper.getById(id);

    }


    @Transactional(rollbackFor = Exception.class)
    public void currentConnOp() {
        // DataSourceUtils.getConnection()方法会首先查看当前是否存在事务管理上下文，如果存在就尝试从事务管理上下文拿连接，
        // 如果获取失败，直接从数据源中拿。在获取连接后，如果存在事务管理上下文则把连接绑定上去。
        // 如果DataSourceUtils在没有事务上下文的方法中使用getConnection()获取连接，依然要手动管理这个连接！

        Area a  = new Area();
        a.setAreaName("--------------");
        areaMapper.saveIgnoreNull(a);
        Connection conn = DataSourceUtils.getConnection(dataSource);

        CountDownLatch latch = new CountDownLatch(1);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    PreparedStatement stst = conn.prepareStatement("insert into area(area_name) values ('sfsfsf')");
                    stst.executeUpdate();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }finally {

                    latch.countDown();
                }

            }
        }).start();


        try {
            latch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        throw new BusinessException("");


    }
}
